using System;
using System.Collections.Generic;

using Pixume.Core;



namespace Pixume.World.Cubes
{
	//NOTE container for all the types of cubes that can be handled 
	//chunks will only hold single integers that reference different cube types (sort of like a reference table)
	//wont directly handle textures but will reference a texture manager which will need to be able to stitch together several
	//different textures into one larger one.  will need to set default texture dimensions as well
	//also default audio and sound effects will have to somehow be referenced

	public static class CubeManager
	{
		//handles block id assignment
		private static AssetIDManager mBlockID = new AssetIDManager();
		//stores all cube types with integer lookup (hashtable)
		private static Dictionary<int,CubeType> mCubeLibrary = new Dictionary<int, CubeType>();
		//string lookup for cube types
		private static Dictionary<string,int> mCubeIntFromStringLookup = new Dictionary<string, int>();

		public static void RegisterBlockType (CubeType pNewBlock)
		{
			if (pNewBlock.BlockName() == null || pNewBlock.BlockName().Trim () == "") {
				throw new ArgumentException("Cube Manager: Cannot register block type, CubeType property Name is invalid!");
			}
			if (Exists (pNewBlock.BlockName())) {
				throw new ArgumentException("Cube Manager: Cannot register block type, block [" + pNewBlock.BlockName() + "] already exists!");
			}
			int blockID = mBlockID.GetNewID ();
			mCubeLibrary.Add (blockID,pNewBlock);
			mCubeIntFromStringLookup.Add (pNewBlock.BlockName(),blockID);
		}

		//NOTE: will also need to call cubetype.unload once other resources are added
		public static void UnRegisterBlockType (int pBlockID)
		{
			if (!Exists (pBlockID)) {
				throw new KeyNotFoundException("Cube Manager: Cannot un-register, BlockID [" + pBlockID + "] does not exist!");
			}
			//must remove the intfromstringlookup first
			mBlockID.RemoveID (pBlockID);
			mCubeIntFromStringLookup.Remove (GetBlockName (pBlockID));
			mCubeLibrary.Remove (pBlockID);
		}
		public static void UnRegisterBlockType (string pBlockName)
		{
			if(!Exists (pBlockName)){
				throw new KeyNotFoundException("Cube Manager: Cannot un-register, Block [" + pBlockName + "] does not exist!");
			}
			//must remove the mcubelibrary first
			mBlockID.RemoveID (GetBlockID (pBlockName));
			mCubeLibrary.Remove (GetBlockID (pBlockName));
			mCubeIntFromStringLookup.Remove (pBlockName);
		}

		public static CubeType BlockHandle (int pBlockID)
		{
			return SafeBlock (pBlockID);
		}
		public static CubeType BlockHandle (string pBlockName)
		{
			return SafeBlock (pBlockName);
		}

		//returns block internal ID based upon block's name
		public static int GetBlockID (string pBlockName)
		{
			return mCubeIntFromStringLookup[SafeBlock (pBlockName).BlockName()];
		}
		//returns block name based upon integer ID
		public static string GetBlockName (int pBlockID)
		{
			return SafeBlock(pBlockID).BlockName ();
		}

		//returns whether a particular block is registered or not
		public static bool Exists(int pBlockID)
		{
			return mCubeLibrary.ContainsKey (pBlockID);
		}
		public static bool Exists(string pBlockName)
		{
			return mCubeIntFromStringLookup.ContainsKey (pBlockName);
		}

		//internally checks if a block exists and throws an exception if it cannot be found, or returns safe block
		//if found
		private static CubeType SafeBlock(int pBlockID)
		{
			if (!Exists (pBlockID)){
				throw new KeyNotFoundException("Cube Manager: Unable to find cube ID: " + pBlockID);
			}
			return mCubeLibrary[pBlockID];
		}
		private static CubeType SafeBlock(string pBlockName)
		{
			if (!Exists (pBlockName)) {
				throw new KeyNotFoundException("Cube Manager: Unable to find cube type: " + pBlockName);
			}
			return mCubeLibrary[mCubeIntFromStringLookup[pBlockName]];
		}

		public static void ClearAll()
		{
			int[] keys = new int[mCubeLibrary.Keys.Count];
			mCubeLibrary.Keys.CopyTo (keys,0);

			foreach(int feKey in keys)
			{
				UnRegisterBlockType (feKey);
			}
			mBlockID = new AssetIDManager();
		}

		public static string CubeListString ()
		{
			string retVal = "";
			foreach (int feKey in mCubeLibrary.Keys) {
				retVal += "[" + feKey + "] " + mCubeLibrary[feKey].BlockName() + "\n";
			}

			return retVal;
		}

	}
}
